// SkinableGUIListBox.cpp : implementation file
//

#include "stdafx.h"
#include "SkinableGUIListBox.h"

#include "SkinManager.h"
#include "SkinableGUIBitmapDC.h"

#include "ximage.h"

using namespace SkinableGUI;
// CSkinableGUIListBox

extern unsigned char * GetHomeButtonBuffer();
extern int GetHomeButtonBufferSize();
extern unsigned char * GetHomeButtonFocusBuffer();
extern int GetHomeButtonFocusBufferSize();

extern unsigned char * get_mp_channel_buf();
extern int get_mp_channel_buf_size();
extern unsigned char * get_mp_channel_active_buf();
extern int get_mp_channel_active_buf_size();
extern unsigned char * get_mp_thumb_buf();
extern int get_mp_thumb_buf_size();
extern unsigned char * get_mp_thumb_active_buf();
extern int get_mp_thumb_active_buf_size();

extern unsigned char * get_mp_channel_vert_buf();
extern int get_mp_channel_vert_buf_size();
extern unsigned char * get_mp_channel_active_vert_buf();
extern int get_mp_channel_active_vert_buf_size();
extern unsigned char * get_mp_thumb_vert_buf();
extern int get_mp_thumb_vert_buf_size();
extern unsigned char * get_mp_thumb_active_vert_buf();
extern int get_mp_thumb_active_vert_buf_size();

#define IDT_SELECTED_ITEM 100
#define IDC_HORZ_SCROLL_BAR 10000
#define IDC_VERT_SCROLL_BAR 10001

IMPLEMENT_DYNAMIC(CSkinableGUIListBox, CSkinableGUIWnd)

CSkinableGUIListBox::CSkinableGUIListBox(SkinListBox * pSkinListBox) :
CSkinableGUIWnd(pSkinListBox)
, m_pContentBitmap(NULL)
, m_nHorzPos(0)
, m_nVertPos(0)
, m_nContentWidth(0)
, m_nContentHeight(0)
, m_nItemHeight(1)
, m_nSelectedIndex(-1)
, m_nSelectedItemBitmapCount(0)
, m_nCurrentSelectedImageFrame(1)
{

}

CSkinableGUIListBox::~CSkinableGUIListBox()
{
}


BEGIN_MESSAGE_MAP(CSkinableGUIListBox, CSkinableGUIWnd)
	ON_WM_PAINT()
	ON_WM_DESTROY()
	ON_WM_SIZE()
	ON_WM_KEYUP()
	ON_WM_CREATE()
	ON_WM_TIMER()
	ON_WM_LBUTTONDOWN()
	ON_WM_LBUTTONUP()
	ON_WM_MOUSEMOVE()
	ON_MESSAGE(WM_BITMAPSLIDER_MOVING, OnBitmapSliderMoving)
	ON_MESSAGE(WM_BITMAPSLIDER_MOVED, OnBitmapSliderMoved)
	ON_WM_KILLFOCUS()
	ON_WM_SETFOCUS()
END_MESSAGE_MAP()

// CSkinableGUIListBox message handlers

BOOL CSkinableGUIListBox::Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext)
{
	return CSkinableGUIWnd::Create(NULL, NULL, dwStyle, rect, pParentWnd, nID, pContext);
}

UINT CSkinableGUIListBox::AddString(const CString & item)
{
	UINT nIndex = m_Items.GetCount();

	m_Items.Add(item);

	m_VertScrollBar.SetRange(0, m_Items.GetCount() - 1, TRUE);

	DestroyListBoxPainter();
	DoRefreshWindow();
	return nIndex;
}

CString CSkinableGUIListBox::GetItem(UINT nIndex)
{
	if (nIndex < (UINT)m_Items.GetCount())
		return m_Items[nIndex];

	return _T("");
}

void CSkinableGUIListBox::OnPaint()
{
	CPaintDC dc(this); // device context for painting

	DoWndPaint(&dc);

	SkinListBox * pListBox = dynamic_cast<SkinListBox *>(m_pSkinControl);

	CRect rcClient = CalculateClientArea();

	//Calculate the real rectangle to paint
	CRect rcClip;

	dc.GetClipBox(&rcClip);

	//Paint Content
	if (m_pContentBitmap == NULL)
	{
		PrepareContentPainter(&dc, &rcClient);

		GetClientRect(&rcClip);

		ScrollToVisible(m_VertScrollBar.GetPos());
	}

	CRect rcContent;

	if (rcContent.IntersectRect(&rcClip, &rcClient))
	{
		rcContent.NormalizeRect();

		if (rcContent.Height() % m_nItemHeight != 0)
		{
			rcContent.bottom = rcContent.top +
				rcContent.Height() / m_nItemHeight * m_nItemHeight;
		}

		CRect srcContent(m_nHorzPos + rcContent.left - rcClient.left,
			m_nVertPos + rcContent.top - rcClient.top,
			m_nHorzPos + rcContent.left - rcClient.left + rcContent.Width(),
			m_nVertPos + rcContent.top - rcClient.top + rcContent.Height());

		if (srcContent.right > m_nContentWidth)
			srcContent.right = m_nContentWidth;
		if (srcContent.bottom > m_nContentHeight)
		{
			srcContent.bottom = m_nContentHeight;
		}

		CSkinableGUIBitmapDC tmpDC(&dc, m_pContentBitmap);

#ifdef _WIN32_WCE
		TransparentBlt(dc.GetSafeHdc(),
			rcContent.left, rcContent.top,
			srcContent.Width(), srcContent.Height(),
			tmpDC.GetSafeHdc(),
			srcContent.left, srcContent.top,
			srcContent.Width(), srcContent.Height(),
			GetSysColor(COLOR_WINDOW));
#else
		dc.TransparentBlt(rcContent.left, rcContent.top,
			srcContent.Width(), srcContent.Height(),
			&tmpDC,
			srcContent.left, srcContent.top,
			srcContent.Width(), srcContent.Height(),
			GetSysColor(COLOR_WINDOW));
#endif
	}

	//Paint Horz ScrollBar
	if (pListBox->HorzScroll && pListBox->HorzScrollBarSet)
	{
		CRect rcHorz;
		CRect rcHorzWnd;

		m_HorzScrollBar.GetWindowRect(&rcHorzWnd);

		ScreenToClient(&rcHorzWnd);

		if (rcHorz.IntersectRect(&rcClip, &rcHorzWnd))
		{
			rcHorz.NormalizeRect();

			ClientToScreen(&rcHorz);
			m_HorzScrollBar.ScreenToClient(&rcHorz);

			if (!m_HorzScrollBar.IsWindowVisible())
			{
				if (m_nContentWidth > rcClient.Width())
				{
					m_HorzScrollBar.ShowWindow(SW_SHOW);

					m_HorzScrollBar.GetClientRect(&rcHorz);
				}
			}
			else if (m_nContentWidth < rcClient.Width())
			{
				m_HorzScrollBar.ShowWindow(SW_HIDE);
			}

			m_HorzScrollBar.InvalidateRect(&rcHorz);
			m_HorzScrollBar.UpdateWindow();
		}
	}

	//Paint Vert ScrollBar
	if (pListBox->VertScroll && pListBox->VertScrollBarSet)
	{
		CRect rcVert;
		CRect rcVertWnd;

		m_VertScrollBar.GetWindowRect(&rcVertWnd);
		ScreenToClient(&rcVertWnd);

		if (rcVert.IntersectRect(&rcClip, &rcVertWnd))
		{
			rcVert.NormalizeRect();
			ClientToScreen(&rcVert);
			m_VertScrollBar.ScreenToClient(&rcVert);

			if (!m_VertScrollBar.IsWindowVisible())
			{
				if (m_nContentHeight > rcClient.Height())
				{
					m_VertScrollBar.ShowWindow(SW_SHOW);
					m_VertScrollBar.GetClientRect(&rcVert);
				}
			}
			else if (m_nContentHeight <= rcClient.Height())
			{
				m_VertScrollBar.ShowWindow(SW_HIDE);
			}

			m_VertScrollBar.InvalidateRect(&rcVert);
			m_VertScrollBar.UpdateWindow();
		}
	}
}

void CSkinableGUIListBox::OnDestroy()
{
	CSkinableGUIWnd::OnDestroy();

	DestroyListBoxPainter();

	DestroyItemIndicatorDC();

	if (::IsWindow(m_HorzScrollBar.GetSafeHwnd()))
		m_HorzScrollBar.DestroyWindow();

	if (::IsWindow(m_VertScrollBar.GetSafeHwnd()))
		m_VertScrollBar.DestroyWindow();
}

void CSkinableGUIListBox::OnSize(UINT nType, int cx, int cy)
{
	CSkinableGUIWnd::OnSize(nType, cx, cy);

	if (::IsWindow(GetSafeHwnd()))
	{
		m_nHorzPos = 0;
		m_nVertPos = 0;

		DestroyListBoxPainter();

		CRect rc = CalculateHorzScrollBarArea();

		if (::IsWindow(m_HorzScrollBar.GetSafeHwnd()))
		{
			m_HorzScrollBar.MoveWindow(&rc);
		}

		rc = CalculateVertScrollBarArea();

		if (::IsWindow(m_VertScrollBar.GetSafeHwnd()))
		{
			m_VertScrollBar.MoveWindow(&rc);
		}
	}
}

void CSkinableGUIListBox::DestroyListBoxPainter(void)
{
	if (NULL != m_pContentBitmap)
	{
		delete m_pContentBitmap;

		m_pContentBitmap = NULL;
	}
}

BOOL CSkinableGUIListBox::CreateEx(DWORD dwExStyle, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, LPVOID lpParam)
{
	return CSkinableGUIWnd::CreateEx(dwExStyle, NULL, NULL, dwStyle, rect, pParentWnd, nID, lpParam);
}

void CSkinableGUIListBox::PrepareContentPainter(CDC *  pDC, const CRect & rcContent)
{
	CFont * pFont = GetFont();

	CFont tmpFont;

	COLORREF txtColor, bkColor;

	if (CreateSkinFont(tmpFont, txtColor, bkColor))
	{
		pFont = &tmpFont;
	}

	CFont * pOldFont = NULL;

	if (pFont != NULL)
	{
		pOldFont = pDC->SelectObject(pFont);
	}

	m_nContentWidth = 0;
	m_nContentHeight = 0;
	m_nItemHeight = 1;
	int nMaxLength = 0;

	for(int i = 0; i < m_Items.GetCount(); i++)
	{
		const CString & item = m_Items.GetAt(i);

		CSize size = pDC->GetTextExtent(item, item.GetLength());

		if (size.cx > m_nContentWidth)
		{
			m_nContentWidth = size.cx;
			nMaxLength = item.GetLength();
		}

		m_nContentHeight += size.cy;
		m_nContentHeight += 3;

		m_nItemHeight = size.cy + 3;
	}

	if (m_nItemHeight == 0)
		m_nItemHeight = 1;

	m_nContentHeight += 6;
	m_nContentWidth += 6;

	if (m_nContentWidth < rcContent.Width())
		m_nContentWidth = rcContent.Width();

	if (m_nContentHeight < rcContent.Height())
		m_nContentHeight = rcContent.Height();

	if (m_nContentWidth > rcContent.Width())
	{
		if (::IsWindow(m_HorzScrollBar.GetSafeHwnd()))
		{
			m_HorzScrollBar.SetRange(0, nMaxLength);
		}
	}
	else
	{
		if (::IsWindow(m_HorzScrollBar.GetSafeHwnd()))
		{
			m_HorzScrollBar.SetRange(0, 0);
		}
	}

	m_pContentBitmap = new CBitmap();

	m_pContentBitmap->CreateCompatibleBitmap(pDC, m_nContentWidth, m_nContentHeight);

	CSkinableGUIBitmapDC tmpDC(pDC, m_pContentBitmap);

	CFont * pOldContentFont = NULL;

	if (pFont != NULL)
	{
		pOldContentFont = tmpDC.SelectObject(pFont);
	}

	CRect rcClient(0,0,m_nContentWidth,m_nContentHeight);

	if (m_pSkinControl->BackgroundImageSet)
	{
		m_BackgroundImage.Blt(&tmpDC,
			&rcClient);
	}
	else if (m_pSkinControl->BackgroundColorSet)
	{
		tmpDC.FillSolidRect(&rcClient, m_BackgroundColor);
	}
	else
	{
		tmpDC.FillSolidRect(&rcClient, GetSysColor(COLOR_WINDOW));
	}

	COLORREF oldTextColor = -1;
	COLORREF oldBkColor = -1;

	if (txtColor != (DWORD)-1)
		oldTextColor = tmpDC.SetTextColor(txtColor);
	else
		oldTextColor = tmpDC.SetTextColor(RGB(255,255,255));

	if (bkColor != (DWORD)-1)
		oldBkColor = tmpDC.SetBkColor(bkColor);
	else
		oldBkColor = tmpDC.SetBkColor(GetSysColor(COLOR_WINDOW));

	for(int i = 0; i < m_Items.GetCount(); i++)
	{
		const CString & item = m_Items.GetAt(i);

		CRect rcItem(3, 3 + i *m_nItemHeight, 3 + m_nContentWidth, 3 + i * m_nItemHeight + m_nItemHeight);

		DrawItem(&tmpDC, item, 
			rcItem,
			i == m_nSelectedIndex);
	}


	if (pFont != NULL)
	{
		pDC->SelectObject(pOldFont);
		tmpDC.SelectObject(pOldContentFont);
	}

	tmpDC.SetTextColor(oldTextColor);
	tmpDC.SetBkColor(oldBkColor);
}

void CSkinableGUIListBox::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags)
{
	CSkinableGUIWnd::OnKeyUp(nChar, nRepCnt, nFlags);

	if (nChar == VK_DOWN)
	{
		if (m_nSelectedIndex < m_Items.GetCount() - 1)
		{
			SetSelectedIndex(m_nSelectedIndex + 1);
		}
	}
	else if (nChar == VK_UP)
	{
		if (m_nSelectedIndex > 0)
		{
			SetSelectedIndex(m_nSelectedIndex - 1);
		}
	}
	else if (nChar == VK_RETURN)
	{
		FireSelectionChangeMessage();
	}
}

void CSkinableGUIListBox::SetSelectedIndex(int nSelectedIndex)
{
	KillTimer(IDT_SELECTED_ITEM);
	CClientDC clientDC(this);

	if (m_pContentBitmap != NULL && m_nSelectedIndex >= 0)
	{
		CRect rcSelected =
			GetItemRect(m_nSelectedIndex);

		CSkinableGUIBitmapDC dc(&clientDC, m_pContentBitmap);
		DrawItem(&dc,
			m_Items.GetAt(m_nSelectedIndex),
			rcSelected,
			FALSE,
			1,
			FALSE);

		ContentRectToClient(&rcSelected);
		InvalidateRect(&rcSelected);
	}

	m_nSelectedIndex = nSelectedIndex;

	if (m_pContentBitmap != NULL && m_nSelectedIndex >= 0)
	{
		CRect rcSelected =
			GetItemRect(m_nSelectedIndex);

		CSkinableGUIBitmapDC dc(&clientDC, m_pContentBitmap);
		DrawItem(&dc,
			m_Items.GetAt(m_nSelectedIndex),
			rcSelected,
			TRUE,
			1,
			FALSE);

		ContentRectToClient(&rcSelected);
		InvalidateRect(&rcSelected);
	}

	m_nCurrentSelectedImageFrame = 1;
	SetTimer(IDT_SELECTED_ITEM, 150, NULL);
	ScrollToVisible(m_nSelectedIndex);
}

void SkinableGUI::CSkinableGUIListBox::DrawItem(CDC * pDC,
												const CString & item, 
												const CRect & rcItem , 
												BOOL bSelected,
												int nItemSelectedImageIndex,
												BOOL bDrawString)
{
	CRect rcContent = rcItem;
	CRect rcFocusRect(0,0,rcItem.Height() / 3, rcItem.Height() / 3);

	rcFocusRect.MoveToXY(rcItem.left, 
		rcItem.top + (rcItem.Height() - rcFocusRect.Height()) / 2);

	rcContent.MoveToX(rcFocusRect.right + 5);

	pDC->FillSolidRect(rcFocusRect, GetSysColor(COLOR_WINDOW));

	if (bSelected)
	{
		CSkinableGUIBitmapDC dc(pDC,
			m_pSelectedItemBitmap[nItemSelectedImageIndex]);

#ifdef _WIN32_WCE
		TransparentBlt(pDC->GetSafeHdc(),
			rcFocusRect.left, rcFocusRect.top,
			rcFocusRect.Width(), rcFocusRect.Height(),
			dc.GetSafeHdc(),
			0,0,64,64,
			GetSysColor(COLOR_WINDOW));
#else
		pDC->TransparentBlt(rcFocusRect.left, rcFocusRect.top,
			rcFocusRect.Width(), rcFocusRect.Height(),
			&dc,
			0,0,64,64,
			GetSysColor(COLOR_WINDOW));
#endif
	}
	else
	{
		CSkinableGUIBitmapDC dc(pDC,
			m_pSelectedItemBitmap[0]);

#ifdef _WIN32_WCE
		TransparentBlt(pDC->GetSafeHdc(),
			rcFocusRect.left, rcFocusRect.top,
			rcFocusRect.Width(), rcFocusRect.Height(),
			dc.GetSafeHdc(),
			0,0,64,64,
			GetSysColor(COLOR_WINDOW));
#else
		pDC->TransparentBlt(rcFocusRect.left, rcFocusRect.top,
			rcFocusRect.Width(), rcFocusRect.Height(),
			&dc,
			0,0,64,64,
			GetSysColor(COLOR_WINDOW));
#endif
	}

	if (bDrawString)
	{
		pDC->DrawText(item,
			item.GetLength(),
			&rcContent,
			0);
	}
}

CRect CSkinableGUIListBox::GetItemRect(int nIndex)
{
	return CRect(3, 
		3 + nIndex * m_nItemHeight, 
		3 + m_nContentWidth, 
		3 + nIndex * m_nItemHeight + m_nItemHeight);
}

void CSkinableGUIListBox::ClearContent()
{
	m_Items.RemoveAll();
	m_ItemDatas.clear();
	m_nSelectedIndex = -1;

	m_nHorzPos = 0;
	m_nVertPos = 0;
	if (::IsWindow(m_VertScrollBar.GetSafeHwnd()))
	{
		m_VertScrollBar.SetRange(0, 0);
	}

	if (::IsWindow(m_HorzScrollBar.GetSafeHwnd()))
	{
		m_HorzScrollBar.SetRange(0, 0);
	}
	DestroyListBoxPainter();
	DoRefreshWindow();
}

int SkinableGUI::CSkinableGUIListBox::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	if (CSkinableGUIWnd::OnCreate(lpCreateStruct) == -1)
		return -1;

	PrepareItemIndicatorDC();

	//Set Timer
	SetTimer(IDT_SELECTED_ITEM, 150, NULL);

	SkinListBox * pListBox = dynamic_cast<SkinListBox *>(m_pSkinControl);

	//Create Vert ScrollBar
	if (pListBox->VertScroll && pListBox->VertScrollBarSet)
	{
		CRect rcVert = CalculateVertScrollBarArea();

		CreateScrollBar(m_VertScrollBar,
			pListBox->VertScrollBar,
			_T("Vert ScrollBar"),
			rcVert,
			m_VertScrollImages,
			TRUE,
			IDC_VERT_SCROLL_BAR);

		m_VertScrollBar.SetVertical(TRUE);
	}

	//Create Horz ScrollBar
	if (pListBox->HorzScroll && pListBox->HorzScrollBarSet)
	{
		CRect rcHorz = CalculateHorzScrollBarArea();

		CreateScrollBar(m_HorzScrollBar,
			pListBox->HorzScrollBar,
			_T("Horz ScrollBar"),
			rcHorz,
			m_HorzScrollImages,
			FALSE,
			IDC_HORZ_SCROLL_BAR);

		m_HorzScrollBar.SetVertical(FALSE);
	}

	return 0;
}

void SkinableGUI::CSkinableGUIListBox::OnTimer(UINT_PTR nIDEvent)
{
	static int delta = 1;

	CSkinableGUIWnd::OnTimer(nIDEvent);

	if (nIDEvent == IDT_SELECTED_ITEM)
	{
		if (m_nSelectedIndex >= 0)
		{
			if (m_nCurrentSelectedImageFrame >= m_nSelectedItemBitmapCount)
			{
				delta = -1;
				m_nCurrentSelectedImageFrame += delta;
			}
			else if (m_nCurrentSelectedImageFrame == 1)
			{
				delta = 1;
			}

			CRect rcSelected =
				GetItemRect(m_nSelectedIndex);

			CClientDC clientDC(this);

			CSkinableGUIBitmapDC dc(&clientDC, m_pContentBitmap);

			DrawItem(&dc,
				m_Items.GetAt(m_nSelectedIndex),
				rcSelected,
				TRUE,
				m_nCurrentSelectedImageFrame,
				FALSE);

			ContentRectToClient(&rcSelected);

			InvalidateRect(&rcSelected);

			m_nCurrentSelectedImageFrame += delta;
		}
	}
}

CRect CSkinableGUIListBox::CalculateClientArea()
{
	SkinListBox * pListBox = dynamic_cast<SkinListBox *>(m_pSkinControl);

	CRect rcClient;

	GetClientRect(rcClient);

	//Calculate the client area
	if (pListBox->HorzScroll && pListBox->HorzScrollBarSet)
	{
		CRect rcHorz = CalculateHorzScrollBarArea();

		if (rcClient.top == rcHorz.top)
		{
			rcClient.top = rcHorz.bottom;
		}
		else
		{
			rcClient.bottom = rcHorz.top;
		}
	}

	if (pListBox->VertScroll && pListBox->VertScrollBarSet)
	{
		CRect rcVert = CalculateVertScrollBarArea();

		if (rcClient.left == rcVert.left)
		{
			rcClient.left = rcVert.right;
		}
		else
		{
			rcClient.right = rcVert.left;
		}
	}

	rcClient.NormalizeRect();

	return rcClient;
}

CRect CSkinableGUIListBox::CalculateHorzScrollBarArea()
{
	SkinListBox * pListBox = dynamic_cast<SkinListBox *>(m_pSkinControl);

	CRect rcClient;

	GetClientRect(rcClient);

	int height = CalculateHorzScrollBarHeight();
	int top = 0;
	int width = rcClient.Width() - CalculateVertScrollBarWidth();
	int left = 0;

	if (pListBox->VertScroll && pListBox->VertScrollBarSet)
	{
		if (pListBox->VertScrollBar.PositionSet)
		{
			if (pListBox->VertScrollBar.Position.DockSet)
			{
				if (pListBox->VertScrollBar.Position.Dock == SkinableGUI::Left)
				{
					left = CalculateVertScrollBarWidth();
				}
			}
		}
	}

	//Calculate the client area
	if (pListBox->HorzScroll && pListBox->HorzScrollBarSet)
	{
		if (pListBox->HorzScrollBar.PositionSet)
		{
			if (pListBox->HorzScrollBar.Position.DockSet)
			{
				if (pListBox->HorzScrollBar.Position.Dock == 
					SkinableGUI::Top)
				{
					top = 0;
				}
				else
				{
					top = rcClient.bottom - height;
				}
			}
			else
			{
				top = rcClient.bottom - height;
			}
		}
		else
		{
			top = rcClient.bottom - height;
		}
	}

	return CRect(left, top, left + width, top + height);
}

CRect CSkinableGUIListBox::CalculateVertScrollBarArea()
{
	SkinListBox * pListBox = dynamic_cast<SkinListBox *>(m_pSkinControl);

	CRect rcClient;

	GetClientRect(rcClient);

	int height = rcClient.Height() - CalculateHorzScrollBarHeight();
	int top = 0;
	int width = CalculateVertScrollBarWidth();
	int left = 0;

	if (pListBox->HorzScroll && pListBox->HorzScrollBarSet)
	{
		if (pListBox->HorzScrollBar.PositionSet)
		{
			if (pListBox->HorzScrollBar.Position.DockSet)
			{
				if (pListBox->HorzScrollBar.Position.Dock == SkinableGUI::Top)
				{
					top = CalculateHorzScrollBarHeight();
				}
			}
		}
	}

	//Calculate the client area
	if (pListBox->VertScroll && pListBox->VertScrollBarSet)
	{
		if (pListBox->VertScrollBar.PositionSet)
		{
			if (pListBox->VertScrollBar.Position.DockSet)
			{
				if (pListBox->VertScrollBar.Position.Dock == 
					SkinableGUI::Left)
				{
					left = 0;
				}
				else
				{
					left = rcClient.right - width;
				}
			}
			else
			{
				left = rcClient.right - width;
			}
		}
		else
		{
			left = rcClient.right - width;
		}
	}

	return CRect(left, top, left + width, top + height);
}

int CSkinableGUIListBox::CalculateHorzScrollBarHeight()
{
	SkinListBox * pListBox = dynamic_cast<SkinListBox *>(m_pSkinControl);

	int height = 0;

	//Calculate the client area
	if (pListBox->HorzScroll && pListBox->HorzScrollBarSet)
	{
		if (pListBox->HorzScrollBar.PositionSet)
		{
			if (pListBox->HorzScrollBar.Position.SizeSet)
			{
				height = pListBox->HorzScrollBar.Position.Size.Height();
			}
		}
		else
		{
			height = 17;
		}
	}

	return height;
}

int CSkinableGUIListBox::CalculateVertScrollBarWidth()
{
	SkinListBox * pListBox = dynamic_cast<SkinListBox *>(m_pSkinControl);

	int width = 0;

	//Calculate the client area
	if (pListBox->VertScroll && pListBox->VertScrollBarSet)
	{
		if (pListBox->VertScrollBar.PositionSet)
		{
			if (pListBox->VertScrollBar.Position.SizeSet)
			{
				width = pListBox->VertScrollBar.Position.Size.Width();
			}
		}
		else
		{
			width = 17;
		}
	}

	return width;
}

void CSkinableGUIListBox::PrepareItemIndicatorDC()
{
	//Prepare Item Image
	m_SelectedItemImage.LoadBuffer(GetHomeButtonFocusBuffer(),
		GetHomeButtonFocusBufferSize());
	m_NormalItemImage.LoadBuffer(GetHomeButtonBuffer(),
		GetHomeButtonBufferSize());

	int nFrames = m_SelectedItemImage.GetNumFrames();

	m_pSelectedItemBitmap = new CBitmap *[nFrames + 1];
	m_nSelectedItemBitmapCount = nFrames + 1;

	CRect rcNormal(0,0,64,64);
	CRect rcSelect(8,8,48,49);

	CDC * pDC = GetDC();

	CDC tmpDC;

	tmpDC.CreateCompatibleDC(pDC);

	CBitmap * pOldBitmap = NULL;

	for(long i = 0; i < m_nSelectedItemBitmapCount; i++)
	{
		m_pSelectedItemBitmap[i] = new CBitmap();
		m_pSelectedItemBitmap[i]->CreateCompatibleBitmap(pDC, 64,64);

		if (pOldBitmap == NULL)
		{
			pOldBitmap =
				tmpDC.SelectObject(m_pSelectedItemBitmap[i]);
		}
		else
		{
			tmpDC.SelectObject(m_pSelectedItemBitmap[i]);
		}

		tmpDC.FillSolidRect(&rcNormal, 
			GetSysColor(COLOR_WINDOW));

		m_NormalItemImage.Blt(&tmpDC,
			&rcNormal);

		if (i > 0)
		{
			m_SelectedItemImage.BltFrame(i - 1, &tmpDC,
				&rcSelect);
		}
	}

	tmpDC.SelectObject(pOldBitmap);
	ReleaseDC(pDC);
}

void CSkinableGUIListBox::DestroyItemIndicatorDC()
{
	if (m_nSelectedItemBitmapCount > 0)
	{
		for(long i = 0; i < m_nSelectedItemBitmapCount; i++)
		{
			delete m_pSelectedItemBitmap[i];
		}

		delete m_pSelectedItemBitmap;
	}
}

void CSkinableGUIListBox::CreateScrollBar(BitmapSlider::CBitmapSlider & slider, 
										  SkinScrollBar & skinScrollBar, 
										  const CString & strTitle,
										  const CRect & rc,
										  CSkinableGUIImage images[4],
										  BOOL bVert,
										  UINT id)
{
	slider.Create(strTitle,
		WS_CHILD,
		rc,
		this,
		id);

	if (skinScrollBar.BackgroundImageSet)
	{
		images[0].Load(&skinScrollBar.BackgroundImage);
		images[1].Load(&skinScrollBar.BackgroundImage);
	}
	else
	{
		if (bVert)
		{
			images[0].LoadBuffer(get_mp_channel_vert_buf(), get_mp_channel_vert_buf_size());
			images[1].LoadBuffer(get_mp_channel_active_vert_buf(), get_mp_channel_active_vert_buf_size());
		}
		else
		{
			images[0].LoadBuffer(get_mp_channel_buf(), get_mp_channel_buf_size());
			images[1].LoadBuffer(get_mp_channel_active_buf(), get_mp_channel_active_buf_size());
		}
	}

	if (skinScrollBar.ThumbImageSet)
	{
		images[2].Load(&skinScrollBar.ThumbImage);
		images[3].Load(&skinScrollBar.ThumbImage);
	}
	else
	{
		if (bVert)
		{
			images[2].LoadBuffer(get_mp_thumb_vert_buf(), get_mp_thumb_vert_buf_size());
			images[3].LoadBuffer(get_mp_thumb_active_vert_buf(), get_mp_thumb_active_vert_buf_size());
		}
		else
		{
			images[2].LoadBuffer(get_mp_thumb_buf(), get_mp_thumb_buf_size());
			images[3].LoadBuffer(get_mp_thumb_active_buf(), get_mp_thumb_active_buf_size());
		}
	}

	slider.SetImages(&images[0], &images[2],
		&images[1], &images[3]);

	slider.SetRange(0, m_Items.GetCount());
	slider.SetPos(0);
	slider.SetPageSize(1);
	slider.SetVertical(bVert);
	slider.DrawFocusRect(FALSE);
}

void SkinableGUI::CSkinableGUIListBox::OnLButtonDown(UINT nFlags, CPoint point)
{
	CRect rcClient = CalculateClientArea();
	CRect rcHorz = CalculateHorzScrollBarArea();
	CRect rcVert = CalculateVertScrollBarArea();

	if (rcClient.PtInRect(point))
	{
		SetFocus();
		SetForegroundWindow();
	}
	else if (!rcHorz.IsRectEmpty() && rcHorz.PtInRect(point))
	{
		if (::IsWindow(m_HorzScrollBar))
		{
			m_HorzScrollBar.SetFocus();
			m_HorzScrollBar.SetForegroundWindow();

			CPoint ptHorz = point;

			ClientToScreen(&ptHorz);
			m_HorzScrollBar.ScreenToClient(&ptHorz);

			m_HorzScrollBar.PostMessage(WM_LBUTTONDOWN,
				(WPARAM)nFlags,
				MAKELPARAM(ptHorz.x, ptHorz.y));
		}
	}
	else if (!rcVert.IsRectEmpty() && rcVert.PtInRect(point))
	{
		if (::IsWindow(m_VertScrollBar))
		{
			m_VertScrollBar.SetFocus();
			m_VertScrollBar.SetForegroundWindow();

			CPoint ptVert = point;

			ClientToScreen(&ptVert);
			m_VertScrollBar.ScreenToClient(&ptVert);

			m_VertScrollBar.PostMessage(WM_LBUTTONDOWN,
				(WPARAM)nFlags,
				MAKELPARAM(ptVert.x, ptVert.y));
		}
	}

	CSkinableGUIWnd::OnLButtonDown(nFlags, point);
}

void SkinableGUI::CSkinableGUIListBox::OnLButtonUp(UINT nFlags, CPoint point)
{
	CRect rcClient = CalculateClientArea();
	CRect rcHorz = CalculateHorzScrollBarArea();
	CRect rcVert = CalculateVertScrollBarArea();

	if (rcClient.PtInRect(point))
	{
		SetFocus();
		SetForegroundWindow();

		for(int i=0;i<m_Items.GetCount();i++)
		{
			CRect rcItem = GetItemRect(i);

			ContentRectToClient(&rcItem);

			if (rcItem.PtInRect(point))
			{
				SetSelectedIndex(i);
				FireSelectionChangeMessage();
				break;
			}
		}
	}
	else if (!rcHorz.IsRectEmpty() && rcHorz.PtInRect(point))
	{
		if (::IsWindow(m_HorzScrollBar))
		{
			m_HorzScrollBar.SetFocus();
			m_HorzScrollBar.SetForegroundWindow();

			CPoint ptHorz = point;

			ClientToScreen(&ptHorz);
			m_HorzScrollBar.ScreenToClient(&ptHorz);

			m_HorzScrollBar.PostMessage(WM_LBUTTONUP,
				(WPARAM)nFlags,
				MAKELPARAM(ptHorz.x, ptHorz.y));
		}
	}
	else if (!rcVert.IsRectEmpty() && rcVert.PtInRect(point))
	{
		if (::IsWindow(m_VertScrollBar))
		{
			m_VertScrollBar.SetFocus();
			m_VertScrollBar.SetForegroundWindow();

			CPoint ptVert = point;

			ClientToScreen(&ptVert);
			m_VertScrollBar.ScreenToClient(&ptVert);

			m_VertScrollBar.PostMessage(WM_LBUTTONUP,
				(WPARAM)nFlags,
				MAKELPARAM(ptVert.x, ptVert.y));
		}
	}

	CSkinableGUIWnd::OnLButtonUp(nFlags, point);
}

void SkinableGUI::CSkinableGUIListBox::OnMouseMove(UINT nFlags, CPoint point)
{
	CRect rcClient = CalculateClientArea();
	CRect rcHorz = CalculateHorzScrollBarArea();
	CRect rcVert = CalculateVertScrollBarArea();

	if (rcClient.PtInRect(point))
	{
		//SetFocus();
		//SetForegroundWindow();
	}
	else if (!rcHorz.IsRectEmpty() && rcHorz.PtInRect(point))
	{
		if (::IsWindow(m_HorzScrollBar))
		{
			m_HorzScrollBar.SetFocus();
			m_HorzScrollBar.SetForegroundWindow();

			CPoint ptHorz = point;

			ClientToScreen(&ptHorz);
			m_HorzScrollBar.ScreenToClient(&ptHorz);

			m_HorzScrollBar.PostMessage(WM_MOUSEMOVE,
				(WPARAM)nFlags,
				MAKELPARAM(ptHorz.x, ptHorz.y));
		}
	}
	else if (!rcVert.IsRectEmpty() && rcVert.PtInRect(point))
	{
		if (::IsWindow(m_VertScrollBar))
		{
			m_VertScrollBar.SetFocus();
			m_VertScrollBar.SetForegroundWindow();

			CPoint ptVert = point;

			ClientToScreen(&ptVert);
			m_VertScrollBar.ScreenToClient(&ptVert);

			m_VertScrollBar.PostMessage(WM_MOUSEMOVE,
				(WPARAM)nFlags,
				MAKELPARAM(ptVert.x, ptVert.y));
		}
	}

	CSkinableGUIWnd::OnMouseMove(nFlags, point);
}

LRESULT CSkinableGUIListBox::OnBitmapSliderMoved(WPARAM wParam, LPARAM lParam)
{
	CString sMsg;
	int pos = (int)lParam;
	int nMax = 0;

	switch( wParam ) 
	{
		case IDC_VERT_SCROLL_BAR:
			m_nVertPos = 3 + pos * m_nItemHeight;
			DoRefreshWindow();
			SetFocus();
			SetForegroundWindow();
			break;
		case IDC_HORZ_SCROLL_BAR:
			nMax = m_HorzScrollBar.GetRangeMax() -
				m_HorzScrollBar.GetRangeMin() + 1;
			m_nHorzPos = 3 + (m_nContentWidth) * pos / nMax;
			DoRefreshWindow();
			SetFocus();
			SetForegroundWindow();
			break;
	}
	return 0;
}

LRESULT CSkinableGUIListBox::OnBitmapSliderMoving(WPARAM wParam, LPARAM lParam)
{
	return 0;
}

void CSkinableGUIListBox::ContentRectToClient(CRect * lpRect)
{
	CRect rcClient = CalculateClientArea();

	lpRect->top = rcClient.top + lpRect->top - m_nVertPos;
	lpRect->bottom = rcClient.top + lpRect->bottom - m_nVertPos;
	lpRect->left = rcClient.left + lpRect->left - m_nHorzPos;
	lpRect->right = rcClient.left + lpRect->right - m_nHorzPos;
}

void CSkinableGUIListBox::ScrollToVisible(UINT nIndex)
{
	if (nIndex >= (UINT)m_Items.GetCount())
	{
		return;
	}

	SkinListBox * pListBox = dynamic_cast<SkinListBox *>(m_pSkinControl);

	if (pListBox->VertScroll && pListBox->VertScrollBarSet)
	{
		CRect rcItem = GetItemRect(nIndex);
		ContentRectToClient(&rcItem);

		CRect rcClient = CalculateClientArea();

		rcClient.bottom = rcClient.top +
			rcClient.Height() / m_nItemHeight * m_nItemHeight;

		if (rcItem.bottom <= rcClient.top)
		{
			m_VertScrollBar.SetPos(nIndex);
			OnBitmapSliderMoved(IDC_VERT_SCROLL_BAR,
				nIndex);
		}
		else if (rcItem.top >= rcClient.bottom)
		{
			m_VertScrollBar.SetPos(nIndex);
			OnBitmapSliderMoved(IDC_VERT_SCROLL_BAR,
				nIndex);
		}
	}
}

void CSkinableGUIListBox::RemoveItem(UINT nIndex)
{
	if (nIndex >= (UINT)m_Items.GetCount())
	{
		return;
	}

	m_Items.RemoveAt(nIndex);

	if (::IsWindow(m_VertScrollBar.GetSafeHwnd()))
	{
		if (m_Items.GetCount() > 0)
		{
			m_VertScrollBar.SetRange(0, m_Items.GetCount() - 1);
			int pos = m_VertScrollBar.GetPos();

			if (pos > m_Items.GetCount() - 1)
			{
				m_VertScrollBar.SetPos(m_Items.GetCount() - 1);
			}
		}
		else
		{
			m_VertScrollBar.SetRange(0, 0);
			m_VertScrollBar.SetPos(0);
		}
	}

	DestroyListBoxPainter();
	DoRefreshWindow();
}

void CSkinableGUIListBox::FireSelectionChangeMessage()
{
	CWnd * pWnd = GetParent();

	if (NULL == pWnd)
		return;

	pWnd->PostMessage(WM_SKINABLE_LISTBOX_SEL_CHANGE,
		MAKEWPARAM(m_nSelectedIndex,0),
		MAKELPARAM(m_pSkinControl->Id,0));
}

void CSkinableGUIListBox::ClientRectToContent(CRect * lpRect)
{
	CRect rcClient = CalculateClientArea();

	lpRect->top = m_nVertPos + lpRect->top - rcClient.top;
	lpRect->bottom = m_nVertPos + lpRect->bottom - rcClient.top;
	lpRect->left = m_nHorzPos + lpRect->left - rcClient.left;
	lpRect->right = m_nHorzPos + lpRect->right - rcClient.left;
}

void SkinableGUI::CSkinableGUIListBox::OnKillFocus(CWnd* pNewWnd)
{
	CSkinableGUIWnd::OnKillFocus(pNewWnd);

	KillTimer(IDT_SELECTED_ITEM);
}

void SkinableGUI::CSkinableGUIListBox::OnSetFocus(CWnd* pOldWnd)
{
	CSkinableGUIWnd::OnSetFocus(pOldWnd);

	if (m_Items.GetCount() > 0 && m_nSelectedIndex < 0)
	{
		SetSelectedIndex(0);
	}
	else
	{
		SetTimer(IDT_SELECTED_ITEM, 150, NULL);
	}
}

void CSkinableGUIListBox::DoRefreshWindow(const RECT * lpRect, BOOL bErase)
{
	CSkinableGUIWnd::DoRefreshWindow(lpRect, bErase);
}
